The objects in the Containers Library are all very easy to use. However, there are certain aspects of the containers that you should be aware of before you start using them. This chapter provides general information about the containers that will let you understand better all the objects in the library.
For detailed information about the methods mentioned in the following chapters, you should consult the included reference guides.
General information
One of the main features of containers that you should be aware of is that they are all dynamic structures. That is, you set the size of the containers at run time instead of setting it at compile time. With a few exceptions, containers are also dynamically sized structures, meaning that you set an initial size, but they can dynamically grow at run time to accommodate your data storage needs.
A second aspect of the containers is that they are polymorphic, so you can store in them any kind of data you want (e.g. objects, records, strings, etc.). Containers achieve this polymorphism by using untyped pointers. This means that you can put anything into a container (although there are some minimal requirements in some cases), but it also means that when you take something back out, the compiler has no way of checking your assumptions about what that something is. Therefore, you should proceed with caution when using a container: if you find that your programs are crashing or locking up, carefully check the types of objects being stored in and read from containers.
Storing non-objects
When using most containers, the first thing you should do is decide the type of data that you want to use: object or non-object data. Based on your decision, you can then choose which container to use. For example, if you want to store records in a simple array, you might use a TStdArray. On the other hand, if you want to store objects, you would use a TStdObjectArray instead. Note, however, that with some containers you can use only object data types. This is the case of linked lists and binary trees, for example.
Most of the time you won't need to worry about the type of data you are using, as long as you choose the right object to store it. Since objects encapsulate all the handling of the data itself, you can use containers to store any object you create. This is usually the case for non-objects too. However, if you want to store special types of non-object data (e.g. records with pointers to data in the heap), you will probably need to create a new descendant container to handle it. In this new descendant you will have to override the GetItem and PutItem methods, which are used to move the data from and to a stream, respectively, and the FreeItem and DoneItem methods, which are used to dispose of data items completely or of portions of them. For more information on any of these methods, please consult the included reference guides.
You might also need to create a new descendant if the container you want to use does not support non-object data of the type you want. For example, if you want to use a collection to store records, you must create a new descendant object to handle this type of data, since no collection object has been included to handle generic non-object data types.
Sorted Containers
Sorted containers include sorted sequences and all graphs. When using sorted containers, there are two methods that you must know about: KeyOf and Compare. KeyOf is used to extract the key used to sort the items in a container from each individual item. Therefore, unless the key is the item itself, you will always need to override this method when using sorted containers. The Compare method is used to compare the keys of two items, to decide which item belongs ahead of the other. By default, Compare assumes that keys are pointers to strings and that items are sorted in ascending order. If you are using non-string keys or want to sort the items in descending order, you must override this method too.